{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Manipulating the Java Classpath and Imports\n",
    "\n",
    "The magic `%classpath` adds jars to the kernel.  The magics `%import` and `%unimport` control which classes are visible by default in your code (in Groovy the regular `import` command is local to the cell where it runs.\n",
    "\n",
    "These magics work in all the BeakerX JVM kernels.\n",
    "\n",
    "## Example\n",
    "\n",
    "This first cell shows that you get an error if you try to import a class not built-in to BeakerX:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import com.example.Demo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then load a jar  into the kernel:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath add jar ../resources/jar/demo.jar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After that, it imports and runs:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import com.example.Demo\n",
    "Demo demo = new Demo();\n",
    "println demo.getObjectTest()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can add multiple jars.  Wildcards also work, like they normally do in the classpath (in this case the code could say `../resources/jar/*`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath add jar ../resources/jar/demo.jar\n",
    "%classpath add jar ../resources/jar/BeakerXClasspathTest.jar\n",
    "\n",
    "println com.example.Demo.staticTest();\n",
    "\n",
    "import com.example.Demo\n",
    "\n",
    "Demo demo = new Demo();\n",
    "println demo.getObjectTest()\n",
    "\n",
    "import com.beaker.BeakerXClasspathTest\n",
    "BeakerXClasspathTest t = new BeakerXClasspathTest();\n",
    "println com.beaker.BeakerXClasspathTest.staticTest;\n",
    "println t.getObjectTest();\n",
    "OutputCell.HIDDEN"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The source code for these jars is in the repository. See [Demo.java](https://github.com/twosigma/beakerx/blob/master/kernel/demoProjects/demo/src/main/java/com/example/Demo.java), and [BeakerXClasspathTest.java](https://github.com/twosigma/beakerx/blob/master/kernel/demoProjects/BeakerXClasspathTest/src/main/java/com/beaker/BeakerXClasspathTest.java)\n",
    "\n",
    "With no arguments the classpath magic prints-out all loaded jars:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is also an API for getting the jars on the classpath:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ClasspathManager.getJars()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading a Single Dependency with Grapes and Maven\n",
    "\n",
    "Groovy has a dependency manager called [Grape](http://docs.groovy-lang.org/latest/html/documentation/grape.html) built-in and you can access it as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@Grab(group='com.google.code.gson', module='gson', version='2.2.4')\n",
    "import com.google.gson.GsonBuilder\n",
    "new GsonBuilder().create().toJson([grab:[]], System.out)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `%classpath` magic also supports loading from [maven central](https://search.maven.org):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath add mvn com.google.code.gson gson 2.2.4\n",
    "new com.google.gson.GsonBuilder().create().toJson([magic:[]], System.out)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also use gradle-like syntax to load dependencies:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath add mvn com.sun.jersey:jersey-core:1.19.4\n",
    "import com.sun.jersey.api.uri.UriBuilderImpl\n",
    "return new UriBuilderImpl()\n",
    "            .path(\"http://beakerx.com/\")\n",
    "            .path(\"documentation\")\n",
    "            .build();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## POM-Type Dependencies\n",
    "\n",
    "Most dependencies are JARs, but a few such as [Jena are POMs](https://jena.apache.org/download/maven.html).  They can be loaded like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath add mvn org.apache.jena apache-jena-libs 3.6.0 pom\n",
    "model = org.apache.jena.rdf.model.ModelFactory.createDefaultModel()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## POM-Classifier Dependencies"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath add mvn org.platanios tensorflow_2.11 0.1.1 jar linux-cpu-x86_64\n",
    "import org.platanios.tensorflow.api.core.Shape\n",
    "Shape.matrix(2,5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Custom Repository\n",
    "\n",
    "The `%classpath config resolver` gives you able to define custom repository:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath config resolver repository.spring.snapshot http://repo.spring.io/snapshot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath add mvn org.springframework spring-context 5.0.3.BUILD-SNAPSHOT"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading Multiple Dependencies with Maven\n",
    "\n",
    "Use the `%%classpath` cell magic to load multiple dependencies at once. This magic creates a POM file containing all the dependencies listed in the cell, solves them together with Maven, and adds the result to the classpath."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%classpath add mvn\n",
    "org.slf4j slf4j-api 1.7.25\n",
    "org.slf4j slf4j-nop 1.7.25"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Loading Multiple Dependencies with exclusions (pom xml style)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%classpath add mvn\n",
    "<dependencies>\n",
    " <dependency>\n",
    "    <groupId>commons-httpclient</groupId>\n",
    "    <artifactId>commons-httpclient</artifactId>\n",
    "    <version>3.1</version>\n",
    "    <exclusions>\n",
    "        <exclusion>\n",
    "            <groupId>commons-logging</groupId>\n",
    "            <artifactId>commons-logging</artifactId>\n",
    "        </exclusion>\n",
    "    </exclusions>\n",
    " </dependency>\n",
    " <dependency>\n",
    "    <groupId>org.slf4j</groupId>\n",
    "    <artifactId>slf4j-api</artifactId>\n",
    "    <version>1.7.26</version>\n",
    " </dependency>\n",
    "</dependencies>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading Jars from a Dynamic Location\n",
    "\n",
    "The above magics work on literal strings.  If you need to compute the location of a jar, use the dynamic classpath magic.  It has two versions one that works with a single string, and another that takes a list of strings:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "location = \"../resources/jar/\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath add dynamic location + \"demo.jar\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath add dynamic [location + \"demo.jar\", location + \"BeakerXClasspathTest.jar\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Location of the Maven Cache and Using a Local Repository\n",
    "\n",
    "Maven normally downloads jars to `~/.m2/repository/`.  But unfortunately this cache is [not safe for concurrent access](https://issues.apache.org/jira/browse/MNG-2802).\n",
    "To avoid corrupting it, BeakerX by default uses its own Maven cache in the conda environment at `$(CONDA_PREFIX)/share/beakerx/maven`.  The `M2_HOME` environment variable overrides the default if set.\n",
    "\n",
    "If you want to use a normal IDE to develop a library, publish it to your local Maven repository, and then load that library into BeakerX, you can, like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath config resolver mvnLocal"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That is shorthand for a `%classpath config resolver local` magic with a `file:` path to the local repository.\n",
    "\n",
    "## Clearing the Maven Cache\n",
    "\n",
    "If you have painted yourself into a corner, you can clear the contents of the maven cache as follows.\n",
    "This is useful for example if you have locally published [non-snapshot artifacts](https://maven.apache.org/guides/getting-started/index.html#What_is_a_SNAPSHOT_version). After resetting the cache, you will be prompted to restart your kernel."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%classpath reset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import and Unimport\n",
    "\n",
    "Normally `import` in Groovy only works in the cell where you use it.  To make a class import automatically into all cells, use `%import` magic."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%import com.twosigma.beakerx.widget.IntSlider\n",
    "w = new IntSlider()\n",
    "w.value = 60\n",
    "w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w2 = new IntSlider()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%unimport com.twosigma.beakerx.widget.IntSlider"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w3 = new IntSlider()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%import static java.lang.Math.PI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "PI"
   ]
  }
 ],
 "metadata": {
  "beakerx_kernel_parameters": {},
  "kernelspec": {
   "display_name": "Groovy",
   "language": "groovy",
   "name": "groovy"
  },
  "language_info": {
   "codemirror_mode": "groovy",
   "file_extension": ".groovy",
   "mimetype": "",
   "name": "Groovy",
   "nbconverter_exporter": "",
   "version": "2.5.6"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": false,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": false,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
